package controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import util.StatusJogo;
import bean.*;
import dao.BolaoDao;
import exception.ExceptionGrupo;

/**
 * Classe Principal. Gerencia tudo do Bolao: Jogadores, Rodadas e Grupos
 * @author Claudio Cardoso, Daniel Leite, Lucas Sampaio, Matheus Sampaio
 * @version 1.0
 */

public class BolaoFacade {

	Bolao bolao;
	BolaoDao bolaoDao;
	
	//construtores
	public BolaoFacade(Bolao bolao) {
		this.bolao = bolao;
		bolaoDao = new BolaoDao(bolao);
	}
	
	public BolaoFacade() {
		this(Sessao.getInstance().getBolao());
	}
	
	//metodos
	/**
	 * Pesquisa Grupo na lista de Grupos
	 * @param nome
	 *      Nome do Grupo. Parametro na pesquisa
	 * @return 
	 * 		Grupo, se o mesmo contem na lista. Null, caso contrario
	 * @throws ExceptionGrupo 
	 */
	public Grupo pesquisaGrupo(String nomeGrupo) throws ExceptionGrupo {
		if (nomeGrupo == null)
			throw new ExceptionGrupo("Grupo null");
		
		for (Grupo grupo : bolao.getGrupos()) {
			if (grupo.getNome().equalsIgnoreCase(nomeGrupo))
				return grupo;
		}

		return null;
	}

	/**
	 * Atualiza Status do Jogo de acordo com o horario
	 */
	public void atualisaStatusDosJogos() {
		// pega a hora atual do pc
		Calendar dateTime = Calendar.getInstance();
		// adiciona 4 horas
		dateTime.add(Calendar.HOUR_OF_DAY, +4);
		// lista dos jogos a serem fechados
		List<Integer> diasDosJogosASeremFechados = new ArrayList<Integer>();

		for (Rodada rodada : bolao.getRodadas()) {

			for (Jogo jogo : rodada.getJogos()) {

				if (jogo.getStatusDoJogo().equals(StatusJogo.FECHADO) || jogo.getStatusDoJogo().equals(StatusJogo.FECHADO_COM_RESULTADO))
					continue;

				/*
				 * Se compareTo retorna um numero maior que zero: dateTime(12h +
				 * 4h) > jogo.getHorario()(15h), significa que o horario atual
				 * somado 4 horas ira passar do horario do jogo, entao
				 * adicionara o dia do jogo na lista.
				 * 
				 * Se compareTo retorna zero: dateTime(16h + 4h) ==
				 * jogo.getHorario()(20h), significa que o horario atual somado
				 * 4 horas eh o msm horario do jogo, entao adicionara o dia do
				 * jogo na lista.
				 * 
				 * Se compareTo retornar um numero menor que zero: dateTime(12 +
				 * 4h) < jogo.getHorario()(22h), nao entrara no if.
				 */

				if (dateTime.compareTo(jogo.getHorario()) >= 0) {
					int diaDoJogo = jogo.getHorario().get(6);

					if (!(diasDosJogosASeremFechados.contains(diaDoJogo)))
						diasDosJogosASeremFechados.add(diaDoJogo);
				}
			}

			// Ira fechar todos os jogos no diaDosJogosASeremFechado
			for (Integer diaDosJogosASeremFechado : diasDosJogosASeremFechados) {
				for (Jogo jogo : rodada.getJogos()) {
					if (jogo.getHorario().get(6) <= diaDosJogosASeremFechado) {
						jogo.setStatusDoJogo(StatusJogo.FECHADO);
					}
				}
			}
		}
	}
	
	/**
	 * Calcula a pontuacao de acordo com o Palpite dado
	 * @param palpite
	 * 		Palpite dado
	 * @param jogo
	 * 		Jogo Palpitado
	 * @return
	 * 		Pontuacao do Jogo Palpitado
	 */
	public int calculaPontuacao(Palpite palpite, Jogo jogo) {
		if (!jogo.getStatusDoJogo().equals(StatusJogo.FECHADO_COM_RESULTADO))
			return -1;
		if (palpite == null)
			return 0;
		
		int palpiteGolsA = palpite.getGolsTimeA();
		int palpiteGolsB = palpite.getGolsTimeB();

		int pontos = 0; 
		if (palpiteGolsA == jogo.getGolsA())
			pontos += 1; 
		if (palpiteGolsB == jogo.getGolsB())
			pontos += 1;

		if ((palpiteGolsA - palpiteGolsB) == 0 && (jogo.getGolsA() - jogo.getGolsB() == 0)) {
			pontos += 2;
		} else if ((palpiteGolsA - palpiteGolsB) > 0 && (jogo.getGolsA() - jogo.getGolsB() > 0)) {
			pontos += 2;
		} else if ((palpiteGolsA - palpiteGolsB) < 0 && (jogo.getGolsA() - jogo.getGolsB() < 0)) {
			pontos += 2;
		}
		
		return pontos;
	}
	
	/**
	 * Atualiza a pontuacao do Jogador
	 */
	public void atualizaPontuacao() {
		for (Jogador jogador : bolao.getJogadores()) {
			jogador.resetPontuacao();
		}

		for (Rodada rodada : bolao.getRodadas()) {
			for (Jogo jogo : rodada.getJogos()) {
				if (jogo.getStatusDoJogo().equals(StatusJogo.FECHADO_COM_RESULTADO)) {
					for (Palpite palpite : jogo.getPalpites()) {
						
						int pontos = calculaPontuacao(palpite, jogo);
						palpite.getJogador().addPontuacao(rodada.getIdentificador(), pontos);
					}
				}
			}
		}
		
		bolaoDao.atualizaDados();
	}

	/**
	 * Pesquisa um Jogador na lista de Todos os Jogadores
	 * @param email
	 *      Paramatro para ser Pesquisado
	 * @return 
	 * 		Retorna o jogador, caso seja encontrado. Null, caso contrario
	 */
	public Jogador pesquisaJogador(String email) {
		for (Jogador jogador : bolao.getJogadores()) {
			if (jogador.getEmail().equalsIgnoreCase(email))
				return jogador;
		}
		return null;
	}
	
	/**
	 * Pesquisa uma Rodada na lista de Todas as Rodadas
	 * @param identificador 
	 * 		Parametro para ser pesquisado
	 * @return Retorna 
	 * 		Rodada, caso seja encontrada. Null, caso contrario
	 */
	public Rodada pesquisaRodada(int identificador) {
		for (Rodada rodada : bolao.getRodadas()) {
			if (rodada.getIdentificador() == identificador)
				return rodada;
		}
		return null;
	}
	
	/**
	 * Adiciona Jogador ao Bolao
	 * @param jogador
	 * 		Jogador a ser Adicionado
	 */
	public void adicionaJogador(Jogador jogador) {
		bolaoDao.adiciona(jogador);		//Polimorfismo
	}

	/**
	 * Adiciona Grupo ao Bolao
	 * @param grupo
	 * 		Grupo a ser Adicionado
	 */
	public void adicionaGrupo(Grupo grupo) {
		bolaoDao.adiciona(grupo);		//Polimorfismo
	}

	/**
	 * Adiciona Rodada ao Bolao
	 * @param rodada
	 * 		Rodada a ser Adicionada
	 */
	public void adicionaRodada(Rodada rodada) {
		bolaoDao.adiciona(rodada);		//Polimorfismo
	}
	
	/**
	 * Adiciona Palpite ao Jogo
	 * @param palpite
	 * 		Palpite a ser Adicionado
	 * @param jogo
	 * 		Jogo Palpitado
	 */
	public void adicionaPalpite(Palpite palpite, Jogo jogo) {
		bolaoDao.adiciona(palpite, jogo);
	}

	/**
	 * Remove Jogador do Bolao
	 * @param email
	 * 		Parametro da Pesquisa: email do Jogador
	 * @return
	 * 		True, se o Jogador for removido com sucesso. False, caso contrario
	 */
	public boolean removeJogador(String email) {
		for (Jogador jogador : bolao.getJogadores()) {
			if (jogador.getEmail().equals(email)) {
				bolaoDao.remove(jogador);
				return true;
			}
		}
		return false;
	}

	/**
	 * Remove Grupo do Bolao
	 * @param grupo
	 * 		Parametro da Pesquisa: Nome do Grupo
	 * @return
	 * 		True, se o grupo for removido com sucesso. False, caso contrario
	 */
	public boolean removeGrupo(Grupo grupo) {
		for (Grupo other : bolao.getGrupos()) {
			if (other.equals(grupo)) {
				bolaoDao.remove(other);
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Remove Rodada do Bolao
	 * @param rodada
	 * 		Parametro da Pesquisa: Rodada a ser removida
	 * @return
	 * 		True, se a rodada for removida com Sucesso. False, caso contrario
	 */
	public boolean removeRodada(Rodada rodada){
		for (Rodada other : bolao.getRodadas()){
			if (other.equals(rodada)){
				bolaoDao.remove(other);
				return true;
			}
		}
		return false;
	}

	/**
	 * Atualiza Dados do Bolao
	 */
	public void atualizaDados() {
		bolaoDao.atualizaDados();
	}
}